package user

import (
	"github.com/jinzhu/gorm"
	"go-gin-api/app/config"
	"go-gin-api/app/model"
	grpcuser "go-gin-api/app/proto/user"
	"go-gin-api/app/util/random"
	"go-gin-api/app/util/stringutil"
	"time"
)

type User struct {
	ID           int       `gorm:"column:id;primary_key" form:"id" json:"id"`
	Username     string    `form:"username" json:"username"`
	Password     string    `form:"password" json:"password"`
	Mobile       int       `form:"mobile" json:"mobile"`
	Status       int       `form:"status" json:"status"`
	Salt         string    `form:"salt" json:"salt"`
	LoginIp      string    `form:"login_ip" json:"login_ip"`
	RegisterTime time.Time `form:"register_time" json:"register_time"`
	LoginTime    time.Time `form:"login_time" json:"login_time"`
	RegisterIp   string    `form:"register_ip" json:"register_ip"`
	CreatedAt    time.Time `form:"created_at" json:"created_at"`
	UpdatedAt    time.Time `form:"updated_at" json:"updated_at"`
}

var field = "id,username,nickname,mobile,avatar,created_at,login_ip,register_time,login_time,register_ip"

type UserRepository interface {
	UserAdd(req *grpcuser.UserRequest) (err error)
	UserDel(req *grpcuser.UserDelRequest) (err error)
	UserUpdate(req *grpcuser.UserUpdateRequest) (err error)
	UserList(req *grpcuser.UserListRequest) (res []User, err error)
	UserInfo(req *grpcuser.UserInfoRequest) (value User, err error)
	UserByName(name string) (value User)
	ExistsUserByName(name string, id int) (res bool)
}

type MysqlUser struct {
}

func NewMysqlUser() UserRepository {
	return &MysqlUser{

	}
}

// 用户新增 UserAdd
func (t *MysqlUser) UserAdd(req *grpcuser.UserRequest) (err error) {
	defer model.Db.Close()
	model.Db = model.Connect()
	salt := random.GenerateSubId(6)
	value := User{
		ID:        0,
		Username:  req.Username,
		Salt:      salt,
		Status:    config.StatusYes,
		Password:  stringutil.MustEncryptString(req.Password + salt),
		Mobile:    int(req.Mobile),
		CreatedAt: time.Now(),
		UpdatedAt: time.Now(),
	}
	err = model.Db.Hander.Model(User{}).Create(&value).Error
	return
}

func (t *MysqlUser) UserDel(req *grpcuser.UserDelRequest) (err error) {
	defer model.Db.Close()
	model.Db = model.Connect()
	var value User
	model.Db.Hander.Model(User{}).Where("id = ?", req.Id).First(&value)
	err = gorm.ErrRecordNotFound
	if value.ID > 0 {
		err = model.Db.Hander.Where("id = ?", req.Id).Delete(&value).Error
	}
	return
}

func (t *MysqlUser) UserByName(name string) (value User) {
	defer model.Db.Close()
	model.Db = model.Connect()
	model.Db.Hander.Model(User{}).Scopes(withLikeUsername(name)).First(&value)
	return
}

func (t *MysqlUser) ExistsUserByName(name string, id int) (res bool) {
	defer model.Db.Close()
	model.Db = model.Connect()
	var count int
	userModel := model.Db.Hander.Model(User{}).Scopes(withLikeUsername(name))
	if id > 0 {
		userModel = userModel.Where("id = ?", id)
	}
	userModel.Count(&count)
	if count > 0 {
		res = true
	}
	return
}

func (t *MysqlUser) UserUpdate(req *grpcuser.UserUpdateRequest) (err error) {
	defer model.Db.Close()
	model.Db = model.Connect()
	var value User
	model.Db.Hander.Model(User{}).Where("id = ?", req.Id).First(&value)
	err = gorm.ErrRecordNotFound
	if value.ID > 0 {
		save := make(map[string]interface{})
		save["username"] = req.Username
		save["mobile"] = int(req.Mobile)
		save["status"] = int(req.Status)
		if req.Password != "" {
			save["password"] = stringutil.MustEncryptString(req.Password + value.Salt)
		}
		// 清除回话
		//todo
		err = model.Db.Hander.Where("id = ?", req.Id).UpdateColumns(&save).Error
	}
	return
}

func (t *MysqlUser) UserList(req *grpcuser.UserListRequest) (res []User, err error) {
	defer model.Db.Close()
	model.Db = model.Connect()
	err = model.Db.Hander.Model(User{}).
		Scopes(withStatus(req.Status), withUsernameLikeName(req.Username), withCreatedAt(req.CreatedAt)).
		Offset((req.Page - 1) * req.Limit).
		Limit(req.Limit).
		Select(field).
		Find(&res).Error
	return
}

func (t *MysqlUser) UserInfo(req *grpcuser.UserInfoRequest) (value User, err error) {
	defer model.Db.Close()
	model.Db = model.Connect()
	err = model.Db.Hander.Model(User{}).Scopes(withTagID(req.Id)).Select(field).First(&value).Error
	return
}

func withStatus(status int32) func(db *gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {
		where := 1
		if status == 0 {
			where = 0
		}
		return db.Where("status = ?", where)
	}
}

func withUsernameLikeName(name string) func(db *gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {
		if name != "" {
			return db.Where("username like %?%", name)
		}
		return db
	}
}

func withLikeUsername(name string) func(db *gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {
		if name != "" {
			return db.Where("username = ?", name)
		}
		return db
	}
}

func withCreatedAt(createdAt string) func(db *gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {
		if createdAt != "" {
			return db.Where("createdAt > ?", createdAt)
		}
		return db
	}
}

func withTagID(id int32) func(db *gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {
		if id > 0 {
			return db.Where("id = ? ", id)
		}
		return db
	}
}
